/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * @file     Mbox.c                                                                           *
 * @brief    SSDK mailbox Driver                                                                   *
 *                                                                                                 *
 **************************************************************************************************/
#include "Mbox.h"
#include "irq.h"

/*
 * For E3650 chip, iram serves as the shared memory for mailbox communication.
 * CONFIG_MBOX_BUF_SIZE defines the size of the mailbox buffer for each core,
 * with a default size of 4096 bytes. Users can redefine this in config.h file.
 * CONFIG_MBOX_BUF_SIZE must be aligned with (SDRV_MBOX_BUF_ALIGN_BYTES * MBOX_MSG_NUM) bytes,
 * range from (SDRV_MBOX_BUF_ALIGN_BYTES * MBOX_MSG_NUM) to
 * (SDRV_MBOX_BUF_ALIGN_BYTES * MBOX_MSG_NUM * 1023U) bytes.
 * The total buffer size for all cores is calculated as CONFIG_MBOX_BUF_SIZE * CORE_NUM.
 */
/* PRQA S 3332 1 */
#if CONFIG_MBOX_BUF_SIZE > 0U
#if (CONFIG_MBOX_BUF_SIZE > ((SDRV_MBOX_BUF_ALIGN_BYTES) * (MBOX_MSG_NUM) * (SDRV_MBOX_BUF_LEN_MASK-1)))
#error "CONFIG_MBOX_BUF_SIZE for a single core exceeds 261888 bytes."
#endif
#if (CONFIG_MBOX_BUF_SIZE % ((SDRV_MBOX_BUF_ALIGN_BYTES) * (MBOX_MSG_NUM)))
#error "CONFIG_MBOX_BUF_SIZE for a single core is not a multiple of 256 bytes."
#endif
#define SDRV_MBOX_BUF_LEN            CONFIG_MBOX_BUF_SIZE
#else
#define SDRV_MBOX_BUF_LEN            4096U
#endif /* #if CONFIG_MBOX_BUF_SIZE */

#define SDRV_MBOX_BUF_BANK_LEN ((SDRV_MBOX_BUF_LEN) / (MBOX_MSG_NUM))
#define SDRV_MBOX_TX_BUF(n)             ((n) * (SDRV_MBOX_BUF_LEN))

#if (defined(CFG_PLATFORM_MCAL))
#define MAILBOX_START_SEC_CODE
#include "Mailbox_MemMap.h"
#endif
/**
 * @brief request available message id.
 *
 * @param[in] sdrv_mbox the structure pointer of the abstract mailbox device.
 * @return available message id.
 *         -1 if no message id is available.
 */
static int32_t sdrv_mbox_alloc_message(sdrv_mbox_t *sdrv_mbox)
{
    int32_t ret = -1;
    uint8_t msg_id;

    for (msg_id = 0U; msg_id < MBOX_MSG_NUM; msg_id++)
    {
        /* PRQA S 4558,1891 1 */
        if (!(sdrv_mbox->msg_bitmap & (1U << msg_id)))
        {
            /* PRQA S 1891 1 */
            sdrv_mbox->msg_bitmap |= (1U << msg_id);
            /* PRQA S 4443 1 */
            ret = msg_id;
            break;
        }
    }

    return ret;
}

/**
 * @brief request available message buffer.
 *
 * The message buffer address must be consecutive in totally 4 (MBOX_MSG_NUM) buffer banks.
 * For example, the value 4'b0110 or 4'b1111 is an valid message buffer mask,
 * while the value 4'b0101 is invalid.
 *
 * @param[in] sdrv_mbox the structure pointer of the abstract mailbox device.
 * @param[in] len the size of the required message buffer.
 * @return available message buffer mask.
 *         -1 if no message buffer is available.
 */
static int32_t sdrv_mbox_alloc_buf_mask(sdrv_mbox_t *sdrv_mbox, uint32_t len)
{
    int32_t ret = -1;
    uint8_t allocated_buf_mask;
    uint8_t start_index;
    /* PRQA S 4461 1 */
    uint8_t required_banks = ((len - 1U) / SDRV_MBOX_BUF_BANK_LEN) + 1U;
    /* PRQA S 4491 1 */
    uint32_t mask = (1U << required_banks) - 1U;

    for (start_index = 0U; start_index <= (MBOX_MSG_NUM - required_banks); start_index++)
    {
        if ((sdrv_mbox->buf_bitmap & (mask << start_index)) == 0U)
        {
            /* PRQA S 4461 1 */
            allocated_buf_mask = mask << start_index;
            sdrv_mbox->buf_bitmap |= allocated_buf_mask;
            /* PRQA S 4443 1 */
            ret = allocated_buf_mask;
            break;
        }
    }

    return ret;
}

/**
 * @brief release the occupied message id.
 *
 * @param[in] sdrv_mbox the structure pointer of the abstract mailbox device.
 * @param[in] msg_id the message id.
 */
static void sdrv_mbox_free_message(sdrv_mbox_t *sdrv_mbox, uint8_t msg_id)
{
    /* PRQA S 1891 1 */
    sdrv_mbox->msg_bitmap &= ~(1U << msg_id);
}

/**
 * @brief call the registered interrupt callback hanlder.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] proc_id the processor id of the sender.
 * @param[in] data the received message data.
 * @param[in] msg the received message length.
 * @return the status of the callback handler.
 *         SDRV_MBOX_STATUS_INVALID_PARAM if chan is NULL or data is NULL.
 */
static int32_t sdrv_mbox_received(const sdrv_mbox_chan_t *sdrv_chan, uint16_t proc_id, uint8_t *data, uint32_t len)
{
    /* PRQA S 4423 1 */
    int32_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

    if ((NULL != sdrv_chan) && (NULL != data))
    {
        /* PRQA S 3344 1 */
        if (sdrv_chan->callback)
        {
            ret = sdrv_chan->callback(sdrv_chan->arg, proc_id, data, len);
        }
    }

    return ret;
}

/**
 * @brief get the tx buffer address.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] buf_mask the buffer mask.
 * @return the address of the tx buffer.
 */
static uint8_t *sdrv_mbox_get_txbuf(const sdrv_mbox_t *dev, uint8_t buf_mask)
{
    uint8_t start_index;
    uint16_t usr_id = Mbox_Ip_GetCpuUserId(dev->base);

    for (start_index  = 0; start_index  < MBOX_MSG_NUM; start_index ++)
    {
        /* PRQA S 3344 1 */
        if (buf_mask & (0x1U << start_index ))
        {
            break;
        }
    }

    /* PRQA S 0306,0488 3 */
    return (uint8_t *)dev->mem_base
            + SDRV_MBOX_TX_BUF(usr_id)
            + (start_index * SDRV_MBOX_BUF_BANK_LEN);
}

/**
 * @brief handle the received meassage.
 *
 * @param[in] proc_id the target processor id.
 * @param[in] short_msg the message.
 * @param[in] msg_len the length of the message.
 * @param[in] arg the parameter of the interrupt handler.
 */
/* PRQA S 3673 2 */
static void sdrv_mbox_handle_msg(uint16_t proc_id, uint64_t short_msg,
                                 uint16_t msg_len, void *arg)
{
    /* PRQA S 0316,3678 1 */
    sdrv_mbox_t *dev = (sdrv_mbox_t *)arg;
    /* PRQA S 3678 1 */
    sdrv_mbox_chan_t *sdrv_chan;
    uint8_t *rx_buf = NULL;
    int32_t chan_id;

    /* PRQA S 3344 1 */
    if (msg_len & SDRV_MBOX_BUF_LEN_MASK)
    {   /* long message */
        /* PRQA S 0306 1 */
        rx_buf = (uint8_t *)(uint32_t)(short_msg & 0xFFFFFFFFU);
        /* PRQA S 1338 1 */
        msg_len = (msg_len & (SDRV_MBOX_BUF_LEN_MASK - 1U)) * SDRV_MBOX_BUF_ALIGN_BYTES;
#if SDRV_MBOX_MANAGE_CACHE
        /* PRQA S 0306,3200 1 */
        LLD_INVALIDATE_CACHE((uint32_t)rx_buf, msg_len);
#endif /* #if SDRV_MBOX_MANAGE_CACHE */
    }

    /* PRQA S 1852 1 */
    for (chan_id = 0; chan_id < dev->chan_num; chan_id++)
    {
        sdrv_chan = &dev->chan[chan_id];

        /* PRQA S 1881,4558,1891 2 */
        if ((true == sdrv_chan->used) && (sdrv_chan->rproc & (1U << proc_id))
            && (sdrv_chan->channel_id == (short_msg >> 48U)))
        {
            /* PRQA S 3344 1 */
            if (rx_buf)
            {
                /* PRQA S 3200 1 */
                sdrv_mbox_received(&dev->chan[chan_id], proc_id, rx_buf, msg_len);
            }
            else
            {
                /* channel_id is masked */
                /* PRQA S 1338,1339 2 */
                short_msg = short_msg & 0xFFFFFFFFFFFFU;
                msg_len *= SDRV_MBOX_MSG_ALIGN_BYTES;
                /* PRQA S 3200,1339 1 */
                sdrv_mbox_received(&dev->chan[chan_id], proc_id, (uint8_t *)&short_msg, msg_len);
            }
        }
    }
}

/**
 * @brief receive the message.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 */
/* PRQA S 1505 1 */
void sdrv_mbox_recv_msg(const sdrv_mbox_t *dev)
{
    Mbox_Ip_RecvMsg(&dev->mbox_rxchan);
}

/**
 * @brief mailbox interrupt handler.
 *
 * @param[in] irq the irq number.
 * @param[in] arg the parameter of the interrupt handler.
 * @return SDRV_MBOX_STATUS_OK if success.
 *         SDRV_MBOX_STATUS_INVALID_PARAM if arg is NULL.
 */
/* PRQA S 3206,3673 1 */
lld_int_t sdrv_mbox_irq_handler(uint32_t irq, void *arg)
{
    /* PRQA S 0316,3678 1 */
    sdrv_mbox_t *dev = (sdrv_mbox_t *)arg;

    irq_log_check_valid(irq);

    sdrv_mbox_recv_msg(dev);

    /* PRQA S 4423 1 */
    return SDRV_MBOX_STATUS_OK;
}

/**
 * @brief handle the wakeup meassage.
 *
 * @param[in] proc_id the target processor id.
 * @param[in] msg the wakeup message.
 * @param[in] arg the parameter of the interrupt handler.
 */
/* PRQA S 3673 1 */
static void sdrv_mbox_handle_wakeup(uint16_t proc_id, uint32_t msg, void *arg)
{
    /* PRQA S 3678,0316 1 */
    sdrv_mbox_t *dev = (sdrv_mbox_t *)arg;

    /* PRQA S 4115 1 */
    if ((NULL != dev) && (dev->wakeup_callback))
    {
        dev->wakeup_callback(dev->wakeup_arg, proc_id, msg);
    }
}

/**
 * @brief mailbox wakeup interrupt handler.
 *
 * @param[in] irq the irq number.
 * @param[in] arg the parameter of the interrupt handler.
 * @return SDRV_MBOX_STATUS_OK if success.
 *         SDRV_MBOX_STATUS_INVALID_PARAM if arg is NULL.
 */
/* PRQA S 3206 1 */
lld_int_t sdrv_mbox_wakeup_irq_handler(uint32_t irq, void *arg)
{
    /* PRQA S 0316 1 */
    sdrv_mbox_t *dev = (sdrv_mbox_t *)arg;
    int32_t msg_id;
    uint32_t msg_src = Mbox_Ip_GetWakeUpSrc(dev->base);

    if (msg_src != 0U)
    { /* wakeup */
        Mbox_Ip_HandleWakeUp(&dev->mbox_wakeupchan);
    }
    else
    { /* transmit ack interrupt */
        /* PRQA S 1822 1 */
        for (msg_id = 0; msg_id < MBOX_MSG_NUM; msg_id++)
        {
            /* PRQA S 3344,4434 1 */
            if (Mbox_Ip_TxDone(dev->base, msg_id))
            {
                /* PRQA S 3200 1 */
                Mbox_Ip_SetTxDone(&dev->mbox_chan[msg_id]);
            }
        }
    }

    /* PRQA S 4423 1 */
    return SDRV_MBOX_STATUS_OK;
}

/**
 * @brief send the short message.
 *
 * The function is used to send short message data.
 * The data length is not more than SDRV_MBOX_SHORT_MSG_LEN bytes.
 * The message data will be stored in the TMH1/2 register.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] data the pointer of the data to be sent.
 * @param[in] len the length of the data to be sent.
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
/* PRQA S 3673 1 */
lld_status_t sdrv_mbox_send_short_msg(sdrv_mbox_chan_t *sdrv_chan, uint8_t *data, uint32_t len,
                                  uint32_t timeout)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;
    sdrv_mbox_t *dev;
    Mbox_Ip_ChnCfgType *mbox_chan;
    uint64_t short_msg = 0U;
    int32_t msg_id;
    uint8_t i;

    if ((NULL != sdrv_chan) && (NULL != sdrv_chan->dev) && (NULL != data))
    {
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_LENGTH_ERROR;
        if ((0UL != len) && (len <= SDRV_MBOX_SHORT_MSG_LEN) &&
            (0U == (len % SDRV_MBOX_MSG_ALIGN_BYTES)))
        {
            dev = sdrv_chan->dev;

            LLD_ENTER_CRITIAL_AREA(irq_flags_0);
            /* request available message id */
            msg_id = sdrv_mbox_alloc_message(dev);
            LLD_EXIT_CRITIAL_AREA(irq_flags_0);

            /* PRQA S 4424 1 */
            ret = SDRV_MBOX_STATUS_NO_CHANNEL;
            if (msg_id >= 0)
            {
                /* splice short message and protocol type */
                for (i = 0U; i < len; i++)
                {
                    short_msg |= ((uint64_t)data[i] << (i * 8U));
                }
                short_msg |= (uint64_t)sdrv_chan->channel_id << 48U;

                mbox_chan = &dev->mbox_chan[msg_id];
                mbox_chan->msgId = (uint8_t)msg_id;
                /* PRQA S 4461 1 */
                mbox_chan->mdp = sdrv_chan->rproc;
                /* PRQA S 4424 1 */
                ret = SDRV_MBOX_STATUS_OK;
                /* PRQA S 1881,4461 2 */
                if (MBOX_OK != Mbox_Ip_SendMsg(mbox_chan, short_msg,
                                               len / SDRV_MBOX_MSG_ALIGN_BYTES, timeout))
                {
                    /* PRQA S 4424 1 */
                    ret = SDRV_MBOX_STATUS_TIMEOUT;
                }

                LLD_ENTER_CRITIAL_AREA(irq_flags_1);
                /* release occupied message id */
                /* PRQA S 4434 1 */
                sdrv_mbox_free_message(dev, msg_id);
                LLD_EXIT_CRITIAL_AREA(irq_flags_1);
            }
        }
    }

    return ret;
}

/**
 * @brief allocate availible buffer.
 *
 * The function is used to allocate the buffers, user will fill message data
 * to the buffers firstly. Then, sdrv_mbox_send is called to send message data.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] len the length of the data to be sent (aliged with SDRV_MBOX_BUF_ALIGN_BYTES bytes).
 * @return the address of the buffer.
 */
uint8_t *sdrv_mbox_alloc_buffer(sdrv_mbox_chan_t *sdrv_chan, uint32_t len)
{
    uint8_t *buf_ptr = NULL;
    sdrv_mbox_t *dev;
    int32_t buf_mask;

    if ((NULL != sdrv_chan) && (NULL != sdrv_chan->dev))
    {
        if (((0UL != len) && (len <= SDRV_MBOX_BUF_LEN)) &&
            (0U == (len % SDRV_MBOX_BUF_ALIGN_BYTES)))
        {
            dev = sdrv_chan->dev;

            LLD_ENTER_CRITIAL_AREA(irq_flags);
            buf_mask = sdrv_mbox_alloc_buf_mask(dev, len);
            if (buf_mask >= 0)
            {
                sdrv_chan->buf_mask = (uint8_t)buf_mask;
                buf_ptr = sdrv_mbox_get_txbuf(dev, sdrv_chan->buf_mask);
            }
            LLD_EXIT_CRITIAL_AREA(irq_flags);
        }
    }

    return buf_ptr;
}

/**
 * @brief release the occupied message buffer.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] buf_id the message buffer id.
 */
void sdrv_mbox_free_buffer(sdrv_mbox_chan_t *sdrv_chan)
{
    sdrv_mbox_t *dev;

    if ((NULL != sdrv_chan) && (NULL != sdrv_chan->dev))
    {
        dev = sdrv_chan->dev;
        LLD_ENTER_CRITIAL_AREA(irq_flags);
        dev->buf_bitmap &= ~sdrv_chan->buf_mask;
        sdrv_chan->buf_mask = 0U;
        LLD_EXIT_CRITIAL_AREA(irq_flags);
    }
}

/**
 * @brief send long message without copy.
 *
 * The function is used to send message data without copying data to the buffers.
 * The function is combined with sdrv_mbox_alloc_buffer which have been allocated the buffers.
 * In addition, user can select a proper memory for message transmission,
 * but you need to pay attention to the cache for the memory.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] data the pointer of the data to be sent.
 * @param[in] len the length of the data to be sent (aliged with SDRV_MBOX_BUF_ALIGN_BYTES bytes).
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
/* PRQA S 3673 1 */
lld_status_t sdrv_mbox_send(sdrv_mbox_chan_t *sdrv_chan, uint8_t *data, uint32_t len,
                        uint32_t timeout)
{
    sdrv_mbox_t *dev;
    Mbox_Ip_ChnCfgType *mbox_chan;
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;
    int32_t msg_id;
    uint64_t short_msg = 0U;

    /* PRQA S 0306 2 */
    if ((NULL != sdrv_chan) && (NULL != sdrv_chan->dev) &&
       (NULL != data) && (0U == ((uint32_t)data % SDRV_MBOX_BUF_ALIGN_BYTES)))
    {
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_LENGTH_ERROR;
        /* length can not exceed 1023U * SDRV_MBOX_BUF_ALIGN_BYTES */
        /* PRQA S 0306 2  */
        if ((0UL != len) && (0U == (len % SDRV_MBOX_BUF_ALIGN_BYTES))
            && ((len / SDRV_MBOX_BUF_ALIGN_BYTES) < SDRV_MBOX_BUF_LEN_MASK))
        {
            dev = sdrv_chan->dev;

            LLD_ENTER_CRITIAL_AREA(irq_flags_0);
            /* request available message id */
            msg_id = sdrv_mbox_alloc_message(dev);
            LLD_EXIT_CRITIAL_AREA(irq_flags_0);

            /* PRQA S 4424 1 */
            ret = SDRV_MBOX_STATUS_NO_CHANNEL;
            if (msg_id >= 0)
            {
#if SDRV_MBOX_MANAGE_CACHE
                /* PRQA S 0306,3200 1 */
                LLD_CLEAN_CACHE((uint32_t)data, len);
#endif /* #if SDRV_MBOX_MANAGE_CACHE */

                /* For long message, length divide by SDRV_MBOX_BUF_ALIGN_BYTES
                * and set the length most bit to 1, mark as long message.
                */
               /* PRQA S 1338,2986,0306 3 */
                len = (len / SDRV_MBOX_BUF_ALIGN_BYTES) | SDRV_MBOX_BUF_LEN_MASK;
                short_msg |= (uint64_t)sdrv_chan->channel_id << 48U;
                short_msg |= (uint32_t)data; /* share memory address */

                mbox_chan = &dev->mbox_chan[msg_id];
                mbox_chan->msgId = (uint8_t)msg_id;
                /* PRQA S 4461 1 */
                mbox_chan->mdp = sdrv_chan->rproc;
                /* PRQA S 4424 1 */
                ret = SDRV_MBOX_STATUS_OK;
                /* PRQA S 1881,4461 1 */
                if (MBOX_OK != Mbox_Ip_SendMsg(mbox_chan, short_msg, len, timeout))
                {
                    /* PRQA S 4424 1 */
                    ret = SDRV_MBOX_STATUS_TIMEOUT;
                }

                LLD_ENTER_CRITIAL_AREA(irq_flags_1);
                /* release occupied message id */
                /* PRQA S 4434 1 */
                sdrv_mbox_free_message(dev, msg_id);
                LLD_EXIT_CRITIAL_AREA(irq_flags_1);
            }
        }
    }

    return ret;
}

/**
 * @brief mailbox wakeup.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] wakeup_msg wakeup message.
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
/* PRQA S 3673 1 */
lld_status_t sdrv_mbox_wakeup(sdrv_mbox_chan_t *sdrv_chan, uint32_t wakeup_msg, uint32_t timeout)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;
    sdrv_mbox_t *dev;
    Mbox_Ip_ChnCfgType *mbox_chan;

    if ((NULL != sdrv_chan) && (NULL != sdrv_chan->dev))
    {
        dev = sdrv_chan->dev;
        mbox_chan = &dev->mbox_wakeupchan;
        /* PRQA S 4461 1 */
        mbox_chan->mdp = sdrv_chan->rproc;
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_OK;
        /* PRQA S 1881 1 */
        if (MBOX_OK != Mbox_Ip_WakeUp(mbox_chan, wakeup_msg, timeout))
        {
            /* PRQA S 4424 1 */
            ret = SDRV_MBOX_STATUS_TIMEOUT;
        }
    }

    return ret;
}

/**
 * @brief config mailbox channel.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] chan_req mailbox channel parameters.
 * @return true if success, otherwise return false.
 */
/* PRQA S 3673 1 */
static bool sdrv_mbox_startup(sdrv_mbox_chan_t *chan, sdrv_mbox_chan_req_t *chan_req)
{
    /* PRQA S 4404 1 */
    bool ret = false;

    /* PRQA S 0499 1 */
    if ((chan_req->rproc < (1U << MBOX_PROC_NUM)) && (0U != chan_req->rproc))
    {
        chan->rproc = chan_req->rproc;
        chan->channel_id = chan_req->channel_id;
        /* PRQA S 4404 1 */
        ret = true;
    }

    return ret;
}

/**
 * @brief request available mailbox channel.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] chan_req mailbox channel parameters.
 * @return the structure pointer of the abstract mailbox channel.
 */
sdrv_mbox_chan_t *sdrv_mbox_request_channel(sdrv_mbox_t *dev, sdrv_mbox_chan_req_t *chan_req)
{
    sdrv_mbox_chan_t *find_chan = NULL;
    uint8_t chan_idx;

    if ((NULL != dev) && (NULL != chan_req))
    {
        for (chan_idx = 0U; chan_idx < dev->chan_num; chan_idx++)
        {
            sdrv_mbox_chan_t *chan = &dev->chan[chan_idx];
            /* PRQA S 4116,4558 1 */
            if (!chan->used)
            {
                /* PRQA S 3344 1 */
                if (sdrv_mbox_startup(chan, chan_req))
                {
                    chan->callback = NULL;
                    chan->arg = NULL;
                    /* PRQA S 4404 1 */
                    chan->used = true;
                    find_chan = chan;
                    break;
                }
            }
        }
    }

    return find_chan;
}

/**
 * @brief release mailbox channel.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan is null.
 */
/* PRQA S 1330 1 */
lld_status_t sdrv_mbox_release_channel(sdrv_mbox_chan_t *sdrv_chan)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

    if (NULL != sdrv_chan)
    {
        sdrv_chan->callback = NULL;
        sdrv_chan->arg = NULL;
        /* PRQA S 4424,4404 1 */
        sdrv_chan->used = false;
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_OK;
    }

    return ret;
}

/**
 * @brief set mailbox callback function.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] callback the callback handler.
 * @param[in] arg the callback parameter.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan or callback is null.
 */
/* PRQA S 1330 1 */
lld_status_t sdrv_mbox_set_callback(sdrv_mbox_chan_t *sdrv_chan, sdrv_mbox_rxcallback callback, void *arg)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

    if ((NULL != sdrv_chan) && (NULL != callback))
    {
        sdrv_chan->callback = callback;
        sdrv_chan->arg = arg;
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_OK;
    }

    return ret;
}

/**
 * @brief set mailbox wakeup callback function.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] callback the wakeup callback handler.
 * @param[in] arg the callback parameter.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan or callback is null.
 */
lld_status_t sdrv_mbox_set_wakeup_callback(sdrv_mbox_t *dev, sdrv_mbox_wakeup_callback callback, void *arg)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

    if ((NULL != dev) && (NULL != callback))
    {
        dev->wakeup_callback = callback;
        dev->wakeup_arg = arg;
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_OK;
    }

    return ret;
}

/**
 * @brief config mailbox device.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] cfg the configuration of the mailbox device.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
/* PRQA S 1505 1 */
lld_status_t sdrv_mbox_early_init(sdrv_mbox_t *dev, const sdrv_mbox_config_t *cfg)
{
    uint8_t index;
    sdrv_mbox_chan_t *chan;
    Mbox_Ip_ChnCfgType *mbox_chan;
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

    if ((NULL != dev) && (NULL != cfg) && (0UL != cfg->base))
    {
        dev->base = cfg->base;
        dev->mem_base = cfg->mem_base;
        dev->irq = cfg->irq;
        dev->wakeup_irq = cfg->wakeup_irq;
        dev->ack_mode = cfg->ack_mode;
        dev->chan_num = SDRV_MBOX_CHN_NUM;

        for (index = 0U; index < dev->chan_num; index++)
        {
            chan = &dev->chan[index];
            chan->dev = dev;
            /* PRQA S 4404 1 */
            chan->used = false;
        }

        /* send channel configuration */
        for (index = 0U; index < MBOX_MSG_NUM; index++)
        {
            mbox_chan = &dev->mbox_chan[index];
            mbox_chan->base = cfg->base;
            mbox_chan->ackMode = cfg->ack_mode;
        }

        /* receive channel configuration */
        mbox_chan = &dev->mbox_rxchan;
        mbox_chan->base = cfg->base;
        mbox_chan->cbFunc = sdrv_mbox_handle_msg;
        /* PRQA S 0314 1 */
        mbox_chan->recvArg = (void *)dev;

        /* wakeup channel configuration */
        mbox_chan = &dev->mbox_wakeupchan;
        mbox_chan->base = cfg->base;
        mbox_chan->wakeupCbFunc = sdrv_mbox_handle_wakeup;
        /* PRQA S 0314 1 */
        mbox_chan->wakeupArg = (void *)dev;

        dev->msg_bitmap = 0U;
        dev->buf_bitmap = 0U;
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_OK;
    }

    return ret;
}

/**
 * @brief initialize mailbox device.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] cfg the configuration of the mailbox device.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_init(sdrv_mbox_t *dev, const sdrv_mbox_config_t *cfg)
{
    lld_status_t ret = sdrv_mbox_early_init(dev, cfg);
    /* PRQA S 1881 1 */
    if (SDRV_MBOX_STATUS_OK == ret)
    {
#if !defined(CFG_PLATFORM_MCAL)
        if (dev->irq >= 0)
        {
            ret = irq_attach((uint32_t)(dev->irq), sdrv_mbox_irq_handler, dev);
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_enable((uint32_t)(dev->irq));
            }
        }

        if (dev->wakeup_irq >= 0)
        {
            ret = irq_attach((uint32_t)(dev->wakeup_irq), sdrv_mbox_wakeup_irq_handler, dev);
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_enable((uint32_t)(dev->wakeup_irq));
            }
        }
#endif
        /* PRQA S 1881 1 */
        if (dev->ack_mode == MBOX_ACK_INTERRUPT_MODE)
        {
            /* PRQA S 4404 EOF */
            Mbox_Ip_EnableAckInterrupt(dev->base, true);
        }
        else
        {
            Mbox_Ip_EnableAckInterrupt(dev->base, false);
        }
    }

    return ret;
}

/**
 * @brief enable/disable mailbox interrupt.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] en 1:enable,0:disable.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
/* PRQA S 3206 1 */
lld_status_t sdrv_mbox_enable_irq(sdrv_mbox_t *dev, bool en)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

#if !defined(CFG_PLATFORM_MCAL)
    if (NULL != dev && dev->irq >= 0)
    {
        if (en)
        {
            ret = irq_attach((uint32_t)(dev->irq), sdrv_mbox_irq_handler, dev);
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_enable((uint32_t)(dev->irq));
            }
        }
        else
        {
            ret = irq_disable((uint32_t)(dev->irq));
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_detach((uint32_t)(dev->irq));
            }
        }
    }
#endif

    return ret;
}

/**
 * @brief enable/disable mailbox wakeup interrupt.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] en 1:enable,0:disable.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
/* PRQA S 3206 1 */
lld_status_t sdrv_mbox_enable_wakeup_irq(sdrv_mbox_t *dev, bool en)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_INVALID_PARAM;

#if !defined(CFG_PLATFORM_MCAL)
    if (NULL != dev && dev->wakeup_irq >= 0)
    {
        if (en)
        {
            ret = irq_attach((uint32_t)(dev->wakeup_irq), sdrv_mbox_wakeup_irq_handler, dev);
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_enable((uint32_t)(dev->wakeup_irq));
            }
        }
        else
        {
            ret = irq_disable((uint32_t)(dev->wakeup_irq));
            if (SDRV_MBOX_STATUS_OK == ret)
            {
                irq_detach((uint32_t)(dev->wakeup_irq));
            }
        }
    }
#endif

    return ret;
}

/**
 * @brief get the master id of mailbox.
 *
 * @param[in] proc_id the mailbox port number.
 */
uint16_t sdrv_mbox_get_master_id(uint16_t proc_id)
{
    return Mbox_Ip_GetMasterId(proc_id);
}

/**
 * @brief set the master id of mailbox.
 *
 * @param[in] base the base physical address.
 */
void sdrv_mbox_set_master_id(uint32_t base)
{
    Mbox_Ip_SetMasterId(base);
}

/**
 * @brief check the master id of mailbox is valid.
 *
 * @param[in] base the base physical address.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_check_master_id(uint32_t base)
{
    /* PRQA S 4424 1 */
    lld_status_t ret = SDRV_MBOX_STATUS_OK;
    /* PRQA S 3344 1 */
    if (Mbox_Ip_CheckMasterId(base))
    {
        /* PRQA S 4424 1 */
        ret = SDRV_MBOX_STATUS_INVALID_MASTERID;
    }

    return ret;
}

#if (defined(CFG_PLATFORM_MCAL))
#define MAILBOX_STOP_SEC_CODE
#include "Mailbox_MemMap.h"
#endif

/* End of file */
